package br.usp.ime.origami.foldcut.gui.listener;

import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.List;

import javax.swing.event.MouseInputListener;

import org.apache.log4j.Logger;

import br.usp.ime.origami.foldcut.gui.canvas.FirstPhaseCanvas;
import br.usp.ime.origami.foldcut.gui.util.Figure;
import br.usp.ime.origami.foldcut.gui.util.OrigamiShape;
import br.usp.ime.origami.foldcut.packing.Disk;
import br.usp.ime.origami.foldcut.packing.FirstPhaseManualPacker;
import br.usp.ime.origami.foldcut.structures.simplegraph.SimpleEdge;
import br.usp.ime.origami.foldcut.structures.simplegraph.Vertex;
import br.usp.ime.origami.model.Point;
import br.usp.ime.origami.model.SimplePoint;
import br.usp.ime.origami.primitives.BasicPrimitives;
import br.usp.ime.origami.primitives.SegmentPrimitives;

public class FirstPhaseDiskPositioningMouseListener implements MouseInputListener
{

	private static final double MINIMUM = 4;

	private Logger logger = Logger.getLogger(FirstPhaseDiskPositioningMouseListener.class);

	private Disk selected = null;

	private FirstPhaseManualPacker packer;

	private double newRay;

	private FirstPhaseCanvas canvas;

	public FirstPhaseDiskPositioningMouseListener(FirstPhaseManualPacker packer, FirstPhaseCanvas canvas)
	{
		this.packer = packer;
		this.canvas = canvas;
		this.repaintCanvas();
	}

	public void mouseClicked(MouseEvent e)
	{
	}

	public void mouseEntered(MouseEvent e)
	{

	}

	public void mouseExited(MouseEvent e)
	{
	}

	public void mousePressed(MouseEvent event)
	{
		Point p = new SimplePoint(event.getPoint().x - 20, event.getPoint().y - 20);

		if (selected == null)
		{
			for (Disk d : packer.getDisks())
			{
				if (d.contains(p))
				{
					logger.info("selected " + d);
					selected = d;
					return;
				}
			}

			for (SimpleEdge e : packer.getGraph().cloneEdges())
			{
				double dps = SegmentPrimitives.distanceToSegment(e, p);

				if (dps < MINIMUM)
				{
					double dip = BasicPrimitives.distance(e.getStart(), p);
					double teta = Math.asin(dps / dip);
					double alfa = Math.cos(teta) * dip;
					double de = e.length();
					double dx = e.getStart().getX() - e.getEnd().getX();
					double dy = e.getStart().getY() - e.getEnd().getY();
					double x =  + e.getStart().getX() - (alfa * dx / de);
					double y =  + e.getStart().getY() - (alfa * dy / de);



					packer.getGraph().remove(e);
					Vertex center = new Vertex(x, y);
					SimpleEdge e1 = new SimpleEdge(e.getStart(), center);
					SimpleEdge e2 = new SimpleEdge(e.getEnd(), center);
					center.setHead(e.getHead());

					e1.setInPaper(e.isInPaper());
					e1.setInPolygon(e.isInPolygon());
					e1.setHead(e.getHead());
					e2.setInPaper(e.isInPaper());
					e2.setInPolygon(e.isInPolygon());
					e2.setHead(e.getHead());
					packer.getGraph().addEdge(e1);
					packer.getGraph().addEdge(e2);
					packer.getGraph().addVertex(center);

					e.getStart().removeAdjacent(e.getEnd());
					e.getEnd().removeAdjacent(e.getStart());

					e.getStart().addAdjacent(center);
					e.getEnd().addAdjacent(center);
					center.addAdjacent(e.getStart());
					center.addAdjacent(e.getEnd());


					selected = new Disk(center, 1);
					selected.setHead(e.getHead());
					packer.addDisk(selected);


				}
			}

		}
		else
		{
			// atualizar Disk do Packer
			logger.info("atualizando " + selected);
			double distance = BasicPrimitives.distance(selected.getCenter(), p);
			Disk d = packer.canChangeDisk(selected, new Disk(selected.getCenter(), distance));
			logger.info("disco proposto tem distancia " + distance);
			logger.info("disco a ser colocad " + d);

			packer.swap(selected, d);
			selected = null;
		}
		repaintCanvas();
	}

	private void repaintCanvas()
	{
		List<OrigamiShape> list = packer.toFigure().getShapes();
		if (selected != null)
		{
			list.addAll(new Disk(selected.getCenter(), newRay).toFigure().getShapes());
		}
		canvas.setFigures(Collections.singletonList(new Figure(list)));
		canvas.repaint();
	}

	public void mouseReleased(MouseEvent e)
	{
	}

	public void mouseDragged(MouseEvent e)
	{
	}

	public void mouseMoved(MouseEvent e)
	{
		if (selected != null)
		{
			Point p = new SimplePoint(e.getPoint().x - 20, e.getPoint().y - 20);
			this.newRay = BasicPrimitives.distance(selected.getCenter(), p);
			repaintCanvas();
		}
	}

	public Disk getSelected()
	{
		return selected;
	}

	public double getNewRay()
	{
		return newRay;
	}

}
